package main

func main() {
	/*
		为什么说 Go 的 map 是无序的？
			1.Go语言中，当我们对 map 进行遍历时，并不是固定地从第一个数开始遍历，每次都是从随机的一个位置开始遍历。
				即使是一个不会改变的 map，仅仅只是遍历它，也不太可能会返回一个固定顺序。
			2.Go的map遍历结果是无序的，本质是上受到两方面的影响：
				“无序”写入 和 扩容
			（1）正常写入（非哈希冲突写入）：虽然buckets是一块连续的内存，但是每次写入都会通过hash记录到某一个bucket上，而不是按照buckets顺序写入
			（2）哈希冲突写入：如果存在hash冲突，会写到同一个bucket上，导致数据的错误
			（3）Go的map扩容有两种：成倍扩容 和 等量扩容。这两种方法都会对内存进行扩容，成倍扩容迫使元素顺序发生变化，导致Go的map遍历结果无序。


		深层理解：
			Go 源码里这样定义 装载因子：
				count 就是 map 的元素个数，2^B 表示 bucket 数量。
			再来说触发 map 扩容的时机：在向 map 插入新 key 的时候，会进行条件检测，符合下面这 2 个条件，就会触发扩容：
				1.装载因子超过阈值，源码里定义的阈值是 6.5。
				2.overflow 的 bucket 数量过多：
					当 B 小于 15，也就是 bucket 总数 2^B 小于 2^15 时，如果 overflow 的 bucket 数量超过 2^B；
					当 B >= 15，也就是 bucket 总数 2^B 大于等于 2^15，如果 overflow 的 bucket 数量超过 2^15。


			1.“无序”写入：
				（1）正常写入（非哈希冲突写入）：是 hash 到某一个 bucket(bmap) 上，而不是按 buckets([]bmap) 的顺序写的
						虽然 buckets([]bmap) 是一块连续的内存空间，但是新写入的键值可能写到这个bucket(bmap)，也可能写到那个bucket(bmap)
				（2）哈希冲突写入：如果存在 hash 冲突，会写到同一个 bucket(bmap) 上的不同的位置上（有可能会写到 溢出桶（overflow）去）

				所以，写数据时，并没有单独维护键值对的顺序

			2.扩容
				（1）Go 的 map 的扩容有两种：
					成倍扩容
					等量扩容
				（2）成倍扩容：
					1.触发条件（两个条件必须同时满足）：
						map写操作时
					   （元素数量 / bucket 数量） > 6.5
					2.扩容过程：
					* 原 buckets([]bmap) 被指向 oldbuckets 变量
					* buckets 变量指向新初始化的成倍的 buckets([]bmap)
					* 写操作触发扩容
					* 每次只扩容当前的键对应的 bucket(bmap)
					* 原 bucket(bmap) 被分流到两个新的 bucket(bmap) 中

					3.由上可得，成倍扩容迫使元素顺序发生变化

				（3）等量扩容：
					1.触发条件：
						overflow 的 bucket 数量过多：
						当 B 小于 15，也就是 bucket 总数 2^B 小于 2^15 时，如果 overflow 的 bucket 数量超过 2^B；
						当 B >= 15，也就是 bucket 总数 2^B 大于等于 2^15，如果 overflow 的 bucket 数量超过 2^15。
					2.等量扩容的目的：
						整理溢出桶，回收冗余的溢出桶
					3.结果：
					（1）整理了正常桶 bmap 的内存
					（2）整理了正常桶 bmap 对应的所有溢出桶 bmap 的内存
					（3）上述整理内存过程之后，多出的溢出桶会被 GC 垃圾回收
	*/
}
